package com.youlu.campus.web.order.service;

import com.alibaba.fastjson.JSON;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.base.order.AddressInfo;
import com.youlu.campus.base.order.GoodsInfo;
import com.youlu.campus.base.order.enums.OrderPayStatusEnum;
import com.youlu.campus.base.order.enums.OrderPayTypeEnum;
import com.youlu.campus.base.order.enums.OrderStatusEnum;
import com.youlu.campus.entity.UserPO;
import com.youlu.campus.entity.VO.PlaceOrderReq;
import com.youlu.campus.entity.WechatConfigInfo;
import com.youlu.campus.entity.WechatMerchantConfig;
import com.youlu.campus.entity.domain.WechatAccessToken;
import com.youlu.campus.service.base.BaseService;
import com.youlu.campus.service.qq.QQConfigInfoService;
import com.youlu.campus.service.qq.QQMiniUserService;
import com.youlu.campus.service.wechat.WechatConfigInfoService;
import com.youlu.campus.service.wechat.WechatH5Service;
import com.youlu.campus.service.wechat.WechatMerchantConfigService;
import com.youlu.campus.web.order.dto.WxPayRequest;
import com.youlu.campus.web.order.entity.OrderPO;
import com.youlu.campus.web.order.entity.OrderRefundPO;
import com.youlu.campus.web.order.entity.UserAddressPO;
import com.youlu.campus.web.order.entity.vo.GoodsVO;
import com.youlu.campus.web.order.service.pay.PayService;
import com.youlu.campus.web.sys.SysConfigService;
import com.youlu.campus.web.sys.po.SysConfigEnum;
import com.youlu.campus.web.sys.po.SysConfigPO;
import com.youlu.campus.web.common.utils.DateTimeUtils;
import com.yuelin.infrastructure.quantum.common.QResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * @author zgz
 * @date 2020/8/31 14:08
 */
@Slf4j
public abstract class OrderBaseService extends BaseService {

    @Value("${sys.qq.appId}")
    protected String appId;

    @Autowired
    protected PayService payService;

    @Autowired
    protected GoodsService goodsService;

    @Autowired
    protected SysConfigService sysConfigService;

    @Autowired
    private WechatH5Service wechatH5Service;
    @Autowired
    private WechatConfigInfoService wechatConfigInfoService;
    /**
     *
     */
    @Value("${sys.pay.wx.wxAppId}")
    private String wxAppId;

    /**
     * AppKey
     */
    @Value("${sys.pay.wx.wxAppSecret}")
    private String wxAppSecret;
    @Autowired
    private QQMiniUserService qQMiniUserService;
    @Autowired
    private QQConfigInfoService qqConfigInfoService;
    @Autowired
    private WechatMerchantConfigService wechatMerchantConfigService;

    public abstract Map<String, String> placeOrder(PlaceOrderReq req);

    public abstract boolean handlePayNotify(OrderPO orderPO);

    protected GoodsVO checkGoods(UserPO user, PlaceOrderReq req) {
        //获取商品信息
        GoodsVO goodsVO = goodsService.getGoodsByCode(req.getGoodsCode());
        if (goodsVO == null) {
            throw new BusinessException("商品不存在或已下架~");
        }
        //判断是否购买过
        if (this.hasOrder(goodsVO.getGoodsCode(), user.getId())) {
            throw new BusinessException("您已领取，请勿重复领取~");
        }
        String whiteList = this.getConfig("whiteList");
        if (StringUtils.isNotBlank(whiteList) && Arrays.asList(whiteList.split(";")).contains(user.getId())) {
            goodsVO.setGoodsPrice(1);
        }
        return goodsVO;
    }

    protected UserAddressPO checkAddress(String addressId) {
        UserAddressPO addressPO = mongoTemplate.findById(addressId, UserAddressPO.class);
        if (addressPO == null) {
            throw new BusinessException("收货地址不存在~");
        }
        return addressPO;
    }

    protected OrderPO saveStandardOrder(UserPO user, GoodsVO goodsVO, UserAddressPO addressPO, PlaceOrderReq req) {
        log.info("saveOrder userId {} applyReq {}", user.getId(), req);
        OrderPO orderPO = new OrderPO();
        String orderNo = goodsVO.getGoodsCode() +
                DateTimeUtils.formatDate(new Date(), "yyyyMMddHHmmssSSS") + (long) (Math.random() * (1000));
        orderPO.setOrderNo(orderNo);
        orderPO.setCreatedTime(new Date());
        orderPO.setPayStatus(OrderPayStatusEnum.WAIT_PAY.getCode());
        orderPO.setStatus(OrderStatusEnum.NEW.getCode());
        orderPO.setUser(super.getUserInfo(user));
        GoodsInfo goods = new GoodsInfo();
        BeanUtils.copyProperties(goodsVO, goods);
        orderPO.setGoods(goods);
        orderPO.setUpdatedTime(new Date());
        AddressInfo address = new AddressInfo();
        if (addressPO != null) {
            BeanUtils.copyProperties(addressPO, address);
            address.setAddressId(addressPO.getId());
        }
        orderPO.setAddress(address);
        orderPO.setSource(req.getSource());
        orderPO.setPayType(req.getPayType());
        orderPO.setPayPrice(goodsVO.getGoodsPrice());
        orderPO.setTotalPrice(goodsVO.getGoodsPrice());
        orderPO.setUpdatedTime(new Date());
        orderPO.setClientIp(req.getClientIp());
        orderPO.setEmail(req.getEmail());
        mongoTemplate.save(orderPO);
        return orderPO;
    }

    protected QResult<Map<String, String>> getUniOrderResult(OrderPO orderPO) {
        log.info(":>>> 统一下单支付接口参数:{}", JSON.toJSON(orderPO));
        Date date = new Date();
        //调用伏羲统一下单接口
        if (orderPO.getPayType().equals(OrderPayTypeEnum.QQ.getCode())) {
            return null;
        }
        if (orderPO.getPayType().equals(OrderPayTypeEnum.WX.getCode())) {
            WxPayRequest payRequest = new WxPayRequest();
            payRequest.setTotalFee(orderPO.getPayPrice());
            payRequest.setDesc(orderPO.getGoods().getGoodsName());
            payRequest.setOrderNo(orderPO.getOrderNo());
            payRequest.setPlatform(orderPO.getPlatform());
            payRequest.setOpenId(orderPO.getOpenId());
            payRequest.setTimeStampStr1(orderPO.getTimestampStr());
            payRequest.setNonceStr(orderPO.getNonceStr());
            payRequest.setWechatAppId(orderPO.getBindWechatAppId());
            payRequest.setPlatform(orderPO.getPlatform());
            //TODO:
            switch (orderPO.getPlatform()) {
                case "qq":
                    payRequest.setAccessToken(qQMiniUserService.getAccessToken(orderPO.getAppId()));
                    payRequest.setAppId(orderPO.getAppId());
                    payRequest.setMerchantId(orderPO.getMerchantId());
                    WechatMerchantConfig merchantConfig = wechatMerchantConfigService.findByMerchantIdAndDecrypt(orderPO.getMerchantId());
                    payRequest.setKey(merchantConfig.getDesc());
                    break;
                case "wechat-mini":
                case "wechat-h5":
                    WechatMerchantConfig merchantConfig1=wechatMerchantConfigService.findByMerchantIdAndDecrypt(orderPO.getMerchantId());
                    WechatConfigInfo configInfo = wechatConfigInfoService.find(orderPO.getAppId());
                    if (Objects.isNull(merchantConfig1)) {
                        log.error(":>>> 微信配置错误:{} ,请联系管理员", orderPO.getAppId());
                        throw new BusinessException("微信配置错误,请联系管理员");
                    }
                    WechatAccessToken wechatAccessToken = wechatH5Service.getAccessToken(configInfo.getAppId(), configInfo.getAppSecret());
                    payRequest.setAccessToken(wechatAccessToken.getAccessToken());
                    payRequest.setAppId(orderPO.getAppId());
                    payRequest.setMerchantId(merchantConfig1.getMerchantId());
                    payRequest.setKey(merchantConfig1.getDesc());
                    break;
                default:
                    break;
            }

            payRequest.setClientIp(orderPO.getClientIp());
            QResult<Map<String, String>> uniOrderResult = payService.unifiedOrder(payRequest);
            return uniOrderResult;
        }
        return null;
    }

    protected boolean handleRefund(String refundId) {
        return true;
    }

    protected OrderRefundPO getOrderRefund(String refundId) {
        return mongoTemplate.findById(refundId, OrderRefundPO.class);
    }

    protected OrderPO getOrder(String orderNo) {
        Query query = new Query();
        query.addCriteria(Criteria.where("orderNo").is(orderNo));
        return mongoTemplate.findOne(query, OrderPO.class);
    }

    private boolean hasOrder(String goodsCode, String userId) {
        log.info("hasPaperCertificateOrder userId {}", userId);
        Query query = new Query();
        query.addCriteria(Criteria.where("user.userId").is(userId));
        query.addCriteria(Criteria.where("goods.goodsCode").is(goodsCode));
        query.addCriteria(Criteria.where("payStatus").is(OrderPayStatusEnum.PAID.getCode()));
        query.addCriteria(Criteria.where("status").in(OrderStatusEnum.PAID_OFF.getCode()
                , OrderStatusEnum.SHIPPED.getCode(), OrderStatusEnum.COMPLETE.getCode()));
        query.addCriteria(Criteria.where("deleted").is(false));
        return mongoTemplate.exists(query, OrderPO.class);
    }

    private String getConfig(String key) {
        SysConfigPO sysConfigPO = sysConfigService.getSysConfig(SysConfigEnum.CIRCULATE_CONFIG);
        if (sysConfigPO != null && sysConfigPO.getConfig() != null) {
            return sysConfigPO.getConfig().get(key);
        }
        return null;
    }
}
